AWS Step Functions ワークフローの構築で AWS CDK の Hotswap deployments を使ってみた
こんにちは、CX事業本部 Delivery部の若槻です。
cdk deploy
で Hotswap deployments を使用すると、CloudFormation を介さずに変更をデプロイできるため、デプロイを高速化することができます。
この Hotswap では、Lambda functions や S3 Bucket Deployments だけでなく、AWS Step Functions State Machines の定義変更もサポートしています。
- Definition changes of AWS Step Functions State Machines.
そこで今回は、AWS Step Functions ワークフローの構築で AWS CDK の Hotswap deployments を使ってみました。
試してみた
最初の CDK コード
最初に次のような定義の State Machine を作成します。
import { aws_stepfunctions, Stack, StackProps } from 'aws-cdk-lib'; import { Construct } from 'constructs'; export class CdkSampleStack extends Stack { public readonly myFileObjectKey: string; constructor(scope: Construct, id: string, props: StackProps) { super(scope, id, props); new aws_stepfunctions.StateMachine(this, 'MyStateMachine', { stateMachineName: 'MyStateMachine', stateMachineType: aws_stepfunctions.StateMachineType.EXPRESS, definitionBody: aws_stepfunctions.ChainDefinitionBody.fromChainable( new aws_stepfunctions.Pass(this, 'MyPassState', { result: aws_stepfunctions.Result.fromObject({ myKey: 'myValue' }), }) ), }); } }
CDK デプロイします。
cdk deploy
デプロイされたステートマシンを同期実行すると結果を取得できました。正常にデプロイが行われています。
$ aws stepfunctions start-sync-execution \ --state-machine-arn ${stateMachineArn} \ --query output | jq -r . {"myKey":"myValue"}
通常の変更デプロイ
続いて、ワークフローの定義を変更してみます。
import { aws_stepfunctions, Stack, StackProps } from 'aws-cdk-lib'; import { Construct } from 'constructs'; export class CdkSampleStack extends Stack { public readonly myFileObjectKey: string; constructor(scope: Construct, id: string, props: StackProps) { super(scope, id, props); new aws_stepfunctions.StateMachine(this, 'MyStateMachine', { stateMachineName: 'MyStateMachine', stateMachineType: aws_stepfunctions.StateMachineType.EXPRESS, definitionBody: aws_stepfunctions.ChainDefinitionBody.fromChainable( new aws_stepfunctions.Pass(this, 'MyPassState', { result: aws_stepfunctions.Result.fromObject({ myKey: 'myValue2' }), }) ), }); } }
CDK デプロイを行うと、完了まで約 20 秒を要しました。
cdk deploy Synthesis time: 2.84s CdkSampleStack: start: Building ed610dcd08cc23e5160d1c309f5a3d26c864aded667a1aae35904e95619ebfc3:current_account-current_region CdkSampleStack: success: Built ed610dcd08cc23e5160d1c309f5a3d26c864aded667a1aae35904e95619ebfc3:current_account-current_region CdkSampleStack: start: Publishing ed610dcd08cc23e5160d1c309f5a3d26c864aded667a1aae35904e95619ebfc3:current_account-current_region CdkSampleStack: success: Published ed610dcd08cc23e5160d1c309f5a3d26c864aded667a1aae35904e95619ebfc3:current_account-current_region CdkSampleStack: deploying... [1/1] CdkSampleStack: creating CloudFormation changeset... CdkSampleStack Deployment time: 17.39s Stack ARN: arn:aws:cloudformation:ap-northeast-1:XXXXXXXXXXXX:stack/CdkSampleStack/e68b6900-f01c-11ed-8538-06bbc29e5367 Total time: 20.23s
当然ですが、ワークフローを実行するとデプロイにより更新されていることが分かります。
$ aws stepfunctions start-sync-execution \ --state-machine-arn ${stateMachineArn} \ --query output | jq -r . {"myKey":"myValue"}
--hotswap
による変更デプロイ
続いて今回の本題である Hotswap deployments を試してみます。
ワークフローの定義をさらに変更します。また、Hotswap の対象とならないリソースとして、AWS SSM Parameter を追加します。
import { aws_stepfunctions, aws_ssm, Stack, StackProps } from 'aws-cdk-lib'; import { Construct } from 'constructs'; export class CdkSampleStack extends Stack { public readonly myFileObjectKey: string; constructor(scope: Construct, id: string, props: StackProps) { super(scope, id, props); // ステートマシン以外のリソースを定義 new aws_ssm.StringParameter(this, 'MyParameter', { parameterName: 'MyParameter', stringValue: 'MyParameterValue', }); new aws_stepfunctions.StateMachine(this, 'MyStateMachine', { stateMachineName: 'MyStateMachine', stateMachineType: aws_stepfunctions.StateMachineType.EXPRESS, definitionBody: aws_stepfunctions.ChainDefinitionBody.fromChainable( new aws_stepfunctions.Pass(this, 'MyPassState', { result: aws_stepfunctions.Result.fromObject({ myKey: 'myValue3' }), }) ), }); } }
ローカルのスタック定義と CloudFormation スタックの差分を確認します。
$ cdk diff Stack CdkSampleStack Resources [+] AWS::SSM::Parameter MyParameter MyParameter18BA547D [~] AWS::StepFunctions::StateMachine MyStateMachine MyStateMachine6C968CA5 └─ [~] DefinitionString ├─ [-] {"StartAt":"MyPassState","States":{"MyPassState":{"Type":"Pass","Result":{"myKey":"myValue2"},"End":true}}} └─ [+] {"StartAt":"MyPassState","States":{"MyPassState":{"Type":"Pass","Result":{"myKey":"myValue3"},"End":true}}}
--hotswap
を使用して Hotswap deployments を行います。すると約 4 秒でデプロイされました。デプロイが高速化されていますね。
$ cdk deploy --hotswap Synthesis time: 3.2s The --hotswap and --hotswap-fallback flags deliberately introduce CloudFormation drift to speed up deployments They should only be used for development - never use them for your production Stacks! CdkSampleStack: start: Building 661e5f2cafaf455ab59361db85609648b9bcdd5272f9a6366e8972228089d215:current_account-current_region CdkSampleStack: success: Built 661e5f2cafaf455ab59361db85609648b9bcdd5272f9a6366e8972228089d215:current_account-current_region CdkSampleStack: start: Publishing 661e5f2cafaf455ab59361db85609648b9bcdd5272f9a6366e8972228089d215:current_account-current_region CdkSampleStack: success: Published 661e5f2cafaf455ab59361db85609648b9bcdd5272f9a6366e8972228089d215:current_account-current_region CdkSampleStack: deploying... [1/1] hotswapping resources: AWS::StepFunctions::StateMachine 'MyStateMachine' AWS::StepFunctions::StateMachine 'MyStateMachine' hotswapped! CdkSampleStack Deployment time: 0.96s Stack ARN: arn:aws:cloudformation:ap-northeast-1:XXXXXXXXXXXX:stack/CdkSampleStack/e68b6900-f01c-11ed-8538-06bbc29e5367 Total time: 4.16s
再度差分を確認すると、Hotswap deployments 前と差分に変更がなく、CloudFormation API ではなく AWS SDK を使用して直接 ワークフロー定義の更新が行われていることが分かります。
$ cdk diff Stack CdkSampleStack Resources [+] AWS::SSM::Parameter MyParameter MyParameter18BA547D [~] AWS::StepFunctions::StateMachine MyStateMachine MyStateMachine6C968CA5 └─ [~] DefinitionString ├─ [-] {"StartAt":"MyPassState","States":{"MyPassState":{"Type":"Pass","Result":{"myKey":"myValue2"},"End":true}}} └─ [+] {"StartAt":"MyPassState","States":{"MyPassState":{"Type":"Pass","Result":{"myKey":"myValue3"},"End":true}}}
ワークフローを実行すると Hotswap deployments によりワークフロー定義が更新されていることが分かります。
$ aws stepfunctions start-sync-execution \ --state-machine-arn ${stateMachineArn} \ --query output | jq -r . {"myKey":"myValue3"}
--hotswap-fallback
による変更デプロイ
--hotswap-fallback
を使用すると、Hotswap deployments をサポートしていないリソースの変更を検知した場合に、Hotswap deployments ではなく通常の変更デプロイが行われます。検知されなかった場合は Hotswap deployments となります。
先程から CDK 定義を変更せずに、--hotswap-fallback
を使用してデプロイを行います。すると通常のデプロイとなりました。
$ cdk deploy --hotswap-fallback Synthesis time: 3.44s The --hotswap and --hotswap-fallback flags deliberately introduce CloudFormation drift to speed up deployments They should only be used for development - never use them for your production Stacks! CdkSampleStack: deploying... [1/1] The following non-hotswappable changes were found: logicalID: MyParameter18BA547D, type: AWS::SSM::Parameter, reason: resource 'MyParameter18BA547D' was created by this deployment Could not perform a hotswap deployment, as the stack CdkSampleStack contains non-Asset changes Falling back to doing a full deployment CdkSampleStack: creating CloudFormation changeset... CdkSampleStack Deployment time: 18.08s Stack ARN: arn:aws:cloudformation:ap-northeast-1:XXXXXXXXXXXX:stack/CdkSampleStack/e68b6900-f01c-11ed-8538-06bbc29e5367 Total time: 21.53s
CloudFormation によるデプロイが行われたので、スタックの差分も解消されています。
$ cdk diff Stack CdkSampleStack There were no differences
その他の検証
ワークフローの定義以外の変更があった場合
ワークフローの定義以外の変更は、Hotswap deployments の対象とならないことを確認してみます。
ワークフローの定義を変更し、またログ出力の設定を行います。
new aws_stepfunctions.StateMachine(this, 'MyStateMachine', { stateMachineName: 'MyStateMachine', stateMachineType: aws_stepfunctions.StateMachineType.EXPRESS, definitionBody: aws_stepfunctions.ChainDefinitionBody.fromChainable( new aws_stepfunctions.Pass(this, 'MyPassState', { result: aws_stepfunctions.Result.fromObject({ myKey: 'myValue4' }), }) ), logs: { destination: new aws_logs.LogGroup(this, 'MyStateMachineLogGroup'), level: aws_stepfunctions.LogLevel.ALL, }, });
Hotswap deployments を行うと、rejected changes: LoggingConfiguration, reason: resource properties 'LoggingConfiguration' are not hotswappable on this resource type
とありログ出力の設定は変更されず、ワークフロー定義の変更のみデプロイされました。
$ cdk deploy --hotswap Synthesis time: 3.52s The --hotswap and --hotswap-fallback flags deliberately introduce CloudFormation drift to speed up deployments They should only be used for development - never use them for your production Stacks! CdkSampleStack: start: Building 0517e4b9f2d793ea4d9c11e823cdd2357ed4cae41a133006bdfc21dc894c8dbe:current_account-current_region CdkSampleStack: success: Built 0517e4b9f2d793ea4d9c11e823cdd2357ed4cae41a133006bdfc21dc894c8dbe:current_account-current_region CdkSampleStack: start: Publishing 0517e4b9f2d793ea4d9c11e823cdd2357ed4cae41a133006bdfc21dc894c8dbe:current_account-current_region CdkSampleStack: success: Published 0517e4b9f2d793ea4d9c11e823cdd2357ed4cae41a133006bdfc21dc894c8dbe:current_account-current_region This deployment will make potentially sensitive changes according to your current security approval level (--require-approval broadening). Please confirm you intend to make the following modifications: IAM Statement Changes ┌───┬──────────┬────────┬─────────────────────────────────┬─────────────────────────────────┬───────────┐ │ │ Resource │ Effect │ Action │ Principal │ Condition │ ├───┼──────────┼────────┼─────────────────────────────────┼─────────────────────────────────┼───────────┤ │ + │ * │ Allow │ logs:CreateLogDelivery │ AWS:${MyStateMachine/Role} │ │ │ │ │ │ logs:DeleteLogDelivery │ │ │ │ │ │ │ logs:DescribeLogGroups │ │ │ │ │ │ │ logs:DescribeResourcePolicies │ │ │ │ │ │ │ logs:GetLogDelivery │ │ │ │ │ │ │ logs:ListLogDeliveries │ │ │ │ │ │ │ logs:PutResourcePolicy │ │ │ │ │ │ │ logs:UpdateLogDelivery │ │ │ └───┴──────────┴────────┴─────────────────────────────────┴─────────────────────────────────┴───────────┘ (NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299) Do you wish to deploy these changes (y/n)? y CdkSampleStack: deploying... [1/1] The following non-hotswappable changes were found. To reconcile these using CloudFormation, specify --hotswap-fallback logicalID: MyStateMachine6C968CA5, type: AWS::StepFunctions::StateMachine, rejected changes: LoggingConfiguration, reason: resource properties 'LoggingConfiguration' are not hotswappable on this resource type hotswapping resources: AWS::StepFunctions::StateMachine 'MyStateMachine' AWS::StepFunctions::StateMachine 'MyStateMachine' hotswapped! CdkSampleStack Deployment time: 1.11s Stack ARN: arn:aws:cloudformation:ap-northeast-1:XXXXXXXXXXXX:stack/CdkSampleStack/e68b6900-f01c-11ed-8538-06bbc29e5367 Total time: 4.63s
念のためワークフローを実行すると、変更後の値 myValue4
が出力され、変更されていることが分かります。
$ aws stepfunctions start-sync-execution \ --state-machine-arn ${stateMachineArn} \ --query output | jq -r . {"myKey":"myValue4"}
ワークフローの定義の変更でワークフロー以外のリソースの変更があった場合
ワークフローの定義の変更でワークフロー以外のリソースの変更があった場合のパターンも試してみます。
ワークフローの定義で SNS Topic への Publish を行うように変更し、Publish 先の SNS Topic を定義します。
import { aws_stepfunctions, aws_stepfunctions_tasks, aws_sns, Stack, StackProps, } from 'aws-cdk-lib'; import { Construct } from 'constructs'; export class CdkSampleStack extends Stack { public readonly myFileObjectKey: string; constructor(scope: Construct, id: string, props: StackProps) { super(scope, id, props); const myTopic = new aws_sns.Topic(this, 'MyTopic', { topicName: 'MyTopic', }); new aws_stepfunctions.StateMachine(this, 'MyStateMachine', { stateMachineName: 'MyStateMachine', stateMachineType: aws_stepfunctions.StateMachineType.EXPRESS, definitionBody: aws_stepfunctions.ChainDefinitionBody.fromChainable( new aws_stepfunctions_tasks.SnsPublish(this, 'MyTask', { topic: myTopic, message: aws_stepfunctions.TaskInput.fromJsonPathAt('$.message'), }) ), }); } }
Hotswap deployments を行うと、rejected changes: IAM, reason: resource 'MyTopic86869434' was created by this deployment
とあり、Hotswap の対象とならないリソースの解決が上手くできていないようです。
$ cdk deploy --hotswap Synthesis time: 3.09s The --hotswap and --hotswap-fallback flags deliberately introduce CloudFormation drift to speed up deployments They should only be used for development - never use them for your production Stacks! This deployment will make potentially sensitive changes according to your current security approval level (--require-approval broadening). Please confirm you intend to make the following modifications: IAM Statement Changes ┌───┬────────────┬────────┬─────────────┬────────────────────────────┬───────────┐ │ │ Resource │ Effect │ Action │ Principal │ Condition │ ├───┼────────────┼────────┼─────────────┼────────────────────────────┼───────────┤ │ + │ ${MyTopic} │ Allow │ sns:Publish │ AWS:${MyStateMachine/Role} │ │ └───┴────────────┴────────┴─────────────┴────────────────────────────┴───────────┘ (NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299) Do you wish to deploy these changes (y/n)? y CdkSampleStack: deploying... [1/1] hotswapping resources: AWS::StepFunctions::StateMachine 'MyStateMachine' Could not perform a hotswap deployment, because the CloudFormation template could not be resolved: Parameter or resource 'MyTopic86869434' could not be found for evaluation CdkSampleStack (no changes) Deployment time: 1.16s Stack ARN: arn:aws:cloudformation:ap-northeast-1:XXXXXXXXXXXX:stack/CdkSampleStack/e68b6900-f01c-11ed-8538-06bbc29e5367 Total time: 4.26s
ワークフローの定義の変更であっても別のリソースの変更が絡む場合は Hotswap deployments が上手く動かない場合があるようです。
おわりに
AWS Step Functions ワークフローの構築で AWS CDK の Hotswap deployments を使ってみました。
ワークフロー定義の変更のデプロイを大きく高速化できることが確認できました。
一方で、ワークフロー定義の変更でワークフロー以外のリソースの変更が絡む場合は Hotswap deployments が上手く動かない場合があるようなので、そういう場合は下記のエントリで紹介している --method=direct
を使用してもデプロイを十分高速化できるので併用をすると良いかと思います。
以上